package cn.bone.springcloud.service.impl;

import cn.bone.springcloud.service.IPaymentService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class PaymentServiceImpl implements IPaymentService {


    /**正常调用的方法*/
    public String paymentInfoSuccess(Integer id){

        StringBuilder builder = new StringBuilder();
        builder.append("当前线程：");
        builder.append(Thread.currentThread().getName());
        builder.append("\t");
        builder.append("payment info success");
        builder.append("\t");
        builder.append("id：");
        builder.append(id);

        return builder.toString();
    }

    /**会延迟几秒钟的方法*/
    /*
        @HystrixProperty(
                name = "execution.isolation.thread.timeoutInMilliseconds",
                value = "3000"
        )
        3s以内算正常的业务逻辑，超过3s报错，走错误处理的逻辑
     */
    @HystrixCommand(fallbackMethod = "paymentInfoTimeoutHandle",
            commandProperties = {
            @HystrixProperty(
                    name = "execution.isolation.thread.timeoutInMilliseconds",
                    value = "5000"
            )
    })
    public String paymentInfoTimeout(Integer id){

        //超时异常会触发服务降级
        int timeNum = 3;

        //运行异常也会触发服务降级
//        int age = 10/0;
        try {
            TimeUnit.SECONDS.sleep(timeNum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        StringBuilder builder = new StringBuilder();
        builder.append("当前线程：");
        builder.append(Thread.currentThread().getName());
        builder.append("\t");
        builder.append("payment info timeout");
        builder.append("\t");
        builder.append("id：");
        builder.append(id);
        builder.append("耗时：");
        builder.append(timeNum);
        builder.append("秒");

        return builder.toString();
    }

    public String paymentInfoTimeoutHandle(Integer id){
        StringBuilder builder = new StringBuilder();
        builder.append("当前线程：");
        builder.append(Thread.currentThread().getName());
        builder.append("\t");
        builder.append("payment info timeout handle");
        builder.append("\t");
        builder.append("id：");
        builder.append(id);

        return builder.toString();
    }



    /***** 下面是服务熔断 *****/
    /**测试服务熔断的方法*/
    // hystrix属性配置说明   https://www.jianshu.com/p/39763a0bd9b8
    // hystrix所有的默认参数，在下面的配置类中
    // com.netflix.hystrix.HystrixCommandProperties

    @HystrixCommand(
            fallbackMethod = "paymentCircuitBreakerFallback",
            commandProperties = {
                    //是否开启断路器
                    //默认值true
                    @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),

                    //设置在一个滚动窗口中，打开断路器的最少请求数。
                    //比如：如果值是20，在一个窗口内（比如10秒），收到19个请求，即使这19个请求都失败了，断路器也不会打开。
                    //默认值：20
                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),

                    //时间窗口期（时间范围）
                    //设置在回路被打开，拒绝请求到再次尝试请求并决定回路是否继续打开的时间。
                    //触发了熔断之后，所有的请求都会被降级，熔断多久后尝试恢复，进入半开状态
                    //这段时间内，所有的请求都会被降级
                    //默认值：5000（毫秒）
                    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "1000"),

                    //在一个滚动的时间窗口内失败率达到多少后跳闸（不是上面的时间窗口）
                    //设置打开回路并启动回退逻辑的错误比率。
                    //默认值：50
                    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")

                    //circuitBreaker.forceOpen
                    //如果该属性设置为true，强制断路器进入打开状态，将会拒绝所有的请求。
                    //该属性优先级比circuitBreaker.forceClosed高。
                    //默认值：false

                    //circuitBreaker.forceClosed
                    //如果该属性设置为true，强制断路器进入关闭状态，将会允许所有的请求，无视错误率。
                    //默认值：false

            }
    )
    public String paymentCircuitBreaker(Integer id){
        if(id < 0){
            throw new RuntimeException("==== id不能为负数");
        }
        String num = UUID.randomUUID().toString();
        String result = Thread.currentThread().getName()
                + "\t"
                + "调用成功，流水号："
                + num;
        return result;
    }

    public String paymentCircuitBreakerFallback(Integer id){
        return "id 不能为负数，请稍后再试！";
    }
}
